這星期二突然發現我們應該做的登入系統還沒做,聽隊友們討論聽得頭皮發麻,太多我聽都沒聽過的專有名詞,但也只能故作鎮定繼續聽下去,討論結束前,試圖用很具體很直白的方式確認我該做的事後,回到位子上,我其實不知道怎麼開始,先研究了一下什麼是pinia,再研究一下前端登入token,老實說我連token是啥都不知道ㄎㄎ,這天的結束,Tim給了我一個功課:去看一下quasar cookies...點頭後帶著滿滿的問號回家去。
在家看完cookies後,我也不知道這到底用來幹嘛?順便把那堆專有名詞查一查,恩~好像很有趣,雖然有趣,問號不減反增,心裡髒話都要飆出來了,隔天Tim居然一早就出現在工作室,根本一盞明燈啊~~趕快巴著他把問號解一解,他也很好心的帶著我一步一步實作,如果沒有他,我根本毫無頭緒,做完後趁還有記憶時趕快把來龍去脈筆記下來,本來說好的V-model你就再等等嘿!這禮拜救火先...
<q-form class="q-gutter-md">
<q-input
filled
v-model="username"
label="Username"
lazy-rules
/>
<q-input
filled
type="password"
v-model="password"
label="Password"
lazy-rules
/>
<div>
<q-btn label="Login" type="submit" color="primary" />
</div>
</q-form>
:rules="[
(val) => !!val || `此欄位必填`,
(val) => /^[a-zA-Z0-9]*$/.test(val) || `請輸入英數字`,
]"
<q-form class="q-gutter-md" @submit="onLogin">
<q-input
filled
v-model="username"
label="Username"
lazy-rules
:rules="[
(val) => !!val || `此欄位必填`,
(val) => /^[a-zA-Z0-9]*$/.test(val) || `請輸入英數字`,
]"
/>
<q-input
filled
type="password"
v-model="password"
label="Password"
lazy-rules
:rules="[
(val) => !!val || `此欄位必填`,
(val) => /^[a-zA-Z0-9]*$/.test(val) || `請輸入英數字`,
]"
/>
<div>
<q-btn label="Login" type="submit" color="primary" />
</div>
</q-form>
const username = ref("");
const password = ref("");
async function onLogin() {
const formData = {
username: username.value,
password: password.value,
};
}
export const useAuthStore = defineStore("auth", {
state: () => ({
token: ref(""),
errorMessage: ref(""),
}),
actions: {
async login(formData) {
try {
const res = await api.post("/auth/login", formData);
if (res.status === 200) {
this.token = res.data.token;
}
} catch (error) {
console.log(error.message);
this.errorMessage = "帳號或密碼有誤";
}
},
export const useAuthStore = defineStore("auth", {
state: () => ({
token: ref(""),
errorMessage: ref(""),
}),
actions: {
async login(formData) {
try {
const res = await api.post("/auth/login", formData);
if (res.status === 200) {
this.token = res.data.token;
//加在這裡
Cookies.set("jwt", this.token);
//加在這裡
}
} catch (error) {
console.log(error.message);
this.errorMessage = "帳號或密碼有誤";
}
},
getTokenFromCookie() {
this.token = Cookies.get("jwt");
if (!this.token) throw new Error();
},
removeJWTCookie() {
Cookies.remove("jwt");
this.token = null
},
const authStore = useAuthStore()
async function onLogin() {
const formData = {
username: username.value,
password: password.value,
};
await authStore.login(formData);
router.push("/");
}
import { onBeforeMount } from "vue";
import { useAuthStore } from "src/stores/auth";
onBeforeMount(() => {
try {
authStore.getTokenFromCookie();
} catch (error) {
router.replace("/login");
}
});
api.interceptors.request.use(
(config) => {
if (authStore.token) {
config.headers.Authorization = `Bearer ${authStore.token}`;
}
return config;
},
function (error) {
// Do something with request error
return Promise.reject(error);
}
);
api.interceptors.response.use(
function (response) {
return response;
},
function (error) {
if (401 === error.response.status) {
authStore.removeJWTCookie();
router.replace("/login");
}
return Promise.reject(error);
}
);
目前實作先到此(汗),之後還可以優化加上過期時間及登出功能。
最後在網路上求解,解方如下:
依樣畫葫蘆後成功了,感謝網路大神~之後Tim跟我講解了一下原理,我們直接引用,在畫面渲染前是拿不到router的,所以必須創一個globalRouter在一開始還沒有接到時預設為null,主要畫面渲染後有router時就變為router,再將globalRouter輸出供axios.js引用即可
6. 經過高人指點,發現我一開始用變數存取token的方式並不優,直接用cookies的方式會簡潔許多,所以從步驟6之後做修改
export const useAuthStore = defineStore("auth", {
state: () => ({
errorMessage: ref(""),
}),
actions: {
async login(formData) {
try {
const res = await api.post("/auth/login", formData);
if (res.status === 200) {
Cookies.set("jwt", res.data.token, { expires: 1 });
}
} catch (error) {
console.log(error.message);
this.errorMessage = "帳號或密碼有誤";
}
},
api.interceptors.request.use(
(config) => {
//加上這行
const token = Cookies.get("jwt");
//加上這行
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
function (error) {
return Promise.reject(error);
}
);
api.interceptors.response.use(
function (response) {
return response;
},
function (error) {
if (error.response.status == 401) {
//修改這一行
Cookies.remove("jwt")
//修該這一行
globalRouter.router.push("/login");
}
return Promise.reject(error);
}
);
onBeforeMount(() => {
if (!Cookies.get("jwt")) router.replace("/login");
});
重構到此告一段落,未來如果又發現更好的方式再繼續更新,人生就是不斷地試誤不斷地進步,大家說是吧(壓力解除後有空講廢話了XD)